home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / cmds / tcsh / dist / sh.dol.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-12-21  |  20.8 KB  |  1,013 lines

  1. /* $Header: /home/hyperion/mu/christos/src/sys/tcsh-6.01/RCS/sh.dol.c,v 3.9 1991/12/19 22:34:14 christos Exp $ */
  2. /*
  3.  * sh.dol.c: Variable substitutions
  4.  */
  5. /*-
  6.  * Copyright (c) 1980, 1991 The Regents of the University of California.
  7.  * All rights reserved.
  8.  *
  9.  * Redistribution and use in source and binary forms, with or without
  10.  * modification, are permitted provided that the following conditions
  11.  * are met:
  12.  * 1. Redistributions of source code must retain the above copyright
  13.  *    notice, this list of conditions and the following disclaimer.
  14.  * 2. Redistributions in binary form must reproduce the above copyright
  15.  *    notice, this list of conditions and the following disclaimer in the
  16.  *    documentation and/or other materials provided with the distribution.
  17.  * 3. All advertising materials mentioning features or use of this software
  18.  *    must display the following acknowledgement:
  19.  *    This product includes software developed by the University of
  20.  *    California, Berkeley and its contributors.
  21.  * 4. Neither the name of the University nor the names of its contributors
  22.  *    may be used to endorse or promote products derived from this software
  23.  *    without specific prior written permission.
  24.  *
  25.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  26.  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  27.  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  28.  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  29.  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  30.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  31.  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  32.  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  33.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  34.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  35.  * SUCH DAMAGE.
  36.  */
  37. #include "sh.h"
  38.  
  39. RCSID("$Id: sh.dol.c,v 3.9 1991/12/19 22:34:14 christos Exp $")
  40.  
  41. /*
  42.  * C shell
  43.  */
  44.  
  45. /*
  46.  * These routines perform variable substitution and quoting via ' and ".
  47.  * To this point these constructs have been preserved in the divided
  48.  * input words.  Here we expand variables and turn quoting via ' and " into
  49.  * QUOTE bits on characters (which prevent further interpretation).
  50.  * If the `:q' modifier was applied during history expansion, then
  51.  * some QUOTEing may have occurred already, so we dont "trim()" here.
  52.  */
  53.  
  54. static int Dpeekc, Dpeekrd;    /* Peeks for DgetC and Dreadc */
  55. static Char *Dcp, **Dvp;    /* Input vector for Dreadc */
  56.  
  57. #define    DEOF    -1
  58.  
  59. #define    unDgetC(c)    Dpeekc = c
  60.  
  61. #define QUOTES        (_Q|_Q1|_ESC)    /* \ ' " ` */
  62.  
  63. /*
  64.  * The following variables give the information about the current
  65.  * $ expansion, recording the current word position, the remaining
  66.  * words within this expansion, the count of remaining words, and the
  67.  * information about any : modifier which is being applied.
  68.  */
  69. #define MAXWLEN (BUFSIZE - 4)
  70. #ifndef COMPAT
  71. #define MAXMOD MAXWLEN        /* This cannot overflow    */
  72. #endif /* COMPAT */
  73. static Char *dolp;        /* Remaining chars from this word */
  74. static Char **dolnxt;        /* Further words */
  75. static int dolcnt;        /* Count of further words */
  76. #ifdef COMPAT
  77. static Char dolmod;        /* : modifier character */
  78. #else
  79. static Char dolmod[MAXMOD];    /* : modifier character */
  80. static int dolnmod;        /* Number of modifiers */
  81. #endif /* COMPAT */
  82. static int dolmcnt;        /* :gx -> 10000, else 1 */
  83. static int dolwcnt;        /* :ax -> 10000, else 1 */
  84.  
  85. static    void     Dfix2        __P((Char **));
  86. static    Char     *Dpack        __P((Char *, Char *));
  87. static    int     Dword        __P((void));
  88. static    void     dolerror    __P((Char *));
  89. static    int     DgetC        __P((int));
  90. static    void     Dgetdol    __P((void));
  91. static    void     fixDolMod    __P((void));
  92. static    void     setDolp    __P((Char *));
  93. static    void     unDredc    __P((int));
  94. static    int     Dredc        __P((void));
  95. static    void     Dtestq        __P((int));
  96.  
  97. /*
  98.  * Fix up the $ expansions and quotations in the
  99.  * argument list to command t.
  100.  */
  101. void
  102. Dfix(t)
  103.     register struct command *t;
  104. {
  105.     register Char **pp;
  106.     register Char *p;
  107.  
  108.     if (noexec)
  109.     return;
  110.     /* Note that t_dcom isn't trimmed thus !...:q's aren't lost */
  111.     for (pp = t->t_dcom; p = *pp++;)
  112.     for (; *p; p++) {
  113.         if (cmap(*p, _DOL | QUOTES)) {    /* $, \, ', ", ` */
  114.         Dfix2(t->t_dcom);    /* found one */
  115.         blkfree(t->t_dcom);
  116.         t->t_dcom = gargv;
  117.         gargv = 0;
  118.         return;
  119.         }
  120.     }
  121. }
  122.  
  123. /*
  124.  * $ substitute one word, for i/o redirection
  125.  */
  126. Char   *
  127. Dfix1(cp)
  128.     register Char *cp;
  129. {
  130.     Char   *Dv[2];
  131.  
  132.     if (noexec)
  133.     return (0);
  134.     Dv[0] = cp;
  135.     Dv[1] = NULL;
  136.     Dfix2(Dv);
  137.     if (gargc != 1) {
  138.     setname(short2str(cp));
  139.     stderror(ERR_NAME | ERR_AMBIG);
  140.     }
  141.     cp = Strsave(gargv[0]);
  142.     blkfree(gargv), gargv = 0;
  143.     return (cp);
  144. }
  145.  
  146. /*
  147.  * Subroutine to do actual fixing after state initialization.
  148.  */
  149. static void
  150. Dfix2(v)
  151.     Char  **v;
  152. {
  153.     ginit();            /* Initialize glob's area pointers */
  154.     Dvp = v;
  155.     Dcp = STRNULL;        /* Setup input vector for Dreadc */
  156.     unDgetC(0);
  157.     unDredc(0);            /* Clear out any old peeks (at error) */
  158.     dolp = 0;
  159.     dolcnt = 0;            /* Clear out residual $ expands (...) */
  160.     while (Dword())
  161.     continue;
  162. }
  163.  
  164. /*
  165.  * Pack up more characters in this word
  166.  */
  167. static Char *
  168. Dpack(wbuf, wp)
  169.     Char   *wbuf, *wp;
  170. {
  171.     register int c;
  172.     register int i = MAXWLEN - (wp - wbuf);
  173.  
  174.     for (;;) {
  175.     c = DgetC(DODOL);
  176.     if (c == '\\') {
  177.         c = DgetC(0);
  178.         if (c == DEOF) {
  179.         unDredc(c);
  180.         *wp = 0;
  181.         Gcat(STRNULL, wbuf);
  182.         return (NULL);
  183.         }
  184.         if (c == '\n')
  185.         c = ' ';
  186.         else
  187.         c |= QUOTE;
  188.     }
  189.     if (c == DEOF) {
  190.         unDredc(c);
  191.         *wp = 0;
  192.         Gcat(STRNULL, wbuf);
  193.         return (NULL);
  194.     }
  195.     if (cmap(c, _SP | _NL | _Q | _Q1)) {    /* sp \t\n'"` */
  196.         unDgetC(c);
  197.         if (cmap(c, QUOTES))
  198.         return (wp);
  199.         *wp++ = 0;
  200.         Gcat(STRNULL, wbuf);
  201.         return (NULL);
  202.     }
  203.     if (--i <= 0)
  204.         stderror(ERR_WTOOLONG);
  205.     *wp++ = c;
  206.     }
  207. }
  208.  
  209. /*
  210.  * Get a word.  This routine is analogous to the routine
  211.  * word() in sh.lex.c for the main lexical input.  One difference
  212.  * here is that we don't get a newline to terminate our expansion.
  213.  * Rather, DgetC will return a DEOF when we hit the end-of-input.
  214.  */
  215. static int
  216. Dword()
  217. {
  218.     register int c, c1;
  219.     Char    wbuf[BUFSIZE];
  220.     register Char *wp = wbuf;
  221.     register int i = MAXWLEN;
  222.     register bool dolflg;
  223.     bool    sofar = 0, done = 0;
  224.  
  225.     while (!done) {
  226.     done = 1;
  227.     c = DgetC(DODOL);
  228.     switch (c) {
  229.  
  230.     case DEOF:
  231.         if (sofar == 0)
  232.         return (0);
  233.         /* finish this word and catch the code above the next time */
  234.         unDredc(c);
  235.         /* fall into ... */
  236.  
  237.     case '\n':
  238.         *wp = 0;
  239.         Gcat(STRNULL, wbuf);
  240.         return (1);
  241.  
  242.     case ' ':
  243.     case '\t':
  244.         done = 0;
  245.         break;
  246.  
  247.     case '`':
  248.         /* We preserve ` quotations which are done yet later */
  249.         *wp++ = c, --i;
  250.     case '\'':
  251.     case '"':
  252.         /*
  253.          * Note that DgetC never returns a QUOTES character from an
  254.          * expansion, so only true input quotes will get us here or out.
  255.          */
  256.         c1 = c;
  257.         dolflg = c1 == '"' ? DODOL : 0;
  258.         for (;;) {
  259.         c = DgetC(dolflg);
  260.         if (c == c1)
  261.             break;
  262.         if (c == '\n' || c == DEOF)
  263.             stderror(ERR_UNMATCHED, c1);
  264.         if ((c & (QUOTE | TRIM)) == ('\n' | QUOTE))
  265.             --wp, ++i;
  266.         if (--i <= 0)
  267.             stderror(ERR_WTOOLONG);
  268.         switch (c1) {
  269.  
  270.         case '"':
  271.             /*
  272.              * Leave any `s alone for later. Other chars are all
  273.              * quoted, thus `...` can tell it was within "...".
  274.              */
  275.             *wp++ = c == '`' ? '`' : c | QUOTE;
  276.             break;
  277.  
  278.         case '\'':
  279.             /* Prevent all further interpretation */
  280.             *wp++ = c | QUOTE;
  281.             break;
  282.  
  283.         case '`':
  284.             /* Leave all text alone for later */
  285.             *wp++ = c;
  286.             break;
  287.  
  288.         default:
  289.             break;
  290.         }
  291.         }
  292.         if (c1 == '`')
  293.         *wp++ = '`' /* i--; eliminated */;
  294.         sofar = 1;
  295.         if ((wp = Dpack(wbuf, wp)) == NULL)
  296.         return (1);
  297.         else {
  298.         i = MAXWLEN - (wp - wbuf);
  299.         done = 0;
  300.         }
  301.         break;
  302.  
  303.     case '\\':
  304.         c = DgetC(0);    /* No $ subst! */
  305.         if (c == '\n' || c == DEOF) {
  306.         done = 0;
  307.         break;
  308.         }
  309.         c |= QUOTE;
  310.         break;
  311.  
  312.     default:
  313.         break;
  314.     }
  315.     if (done) {
  316.         unDgetC(c);
  317.         sofar = 1;
  318.         if ((wp = Dpack(wbuf, wp)) == NULL)
  319.         return (1);
  320.         else {
  321.         i = MAXWLEN - (wp - wbuf);
  322.         done = 0;
  323.         }
  324.     }
  325.     }
  326.     /* Really NOTREACHED */
  327.     return (0);
  328. }
  329.  
  330.  
  331. /*
  332.  * Get a character, performing $ substitution unless flag is 0.
  333.  * Any QUOTES character which is returned from a $ expansion is
  334.  * QUOTEd so that it will not be recognized above.
  335.  */
  336. static int
  337. DgetC(flag)
  338.     register int flag;
  339. {
  340.     register int c;
  341.  
  342. top:
  343.     if (c = Dpeekc) {
  344.     Dpeekc = 0;
  345.     return (c);
  346.     }
  347.     if (lap) {
  348.     c = *lap++ & (QUOTE | TRIM);
  349.     if (c == 0) {
  350.         lap = 0;
  351.         goto top;
  352.     }
  353. quotspec:
  354.     if (cmap(c, QUOTES))
  355.         return (c | QUOTE);
  356.     return (c);
  357.     }
  358.     if (dolp) {
  359.     if (c = *dolp++ & (QUOTE | TRIM))
  360.         goto quotspec;
  361.     if (dolcnt > 0) {
  362.         setDolp(*dolnxt++);
  363.         --dolcnt;
  364.         return (' ');
  365.     }
  366.     dolp = 0;
  367.     }
  368.     if (dolcnt > 0) {
  369.     setDolp(*dolnxt++);
  370.     --dolcnt;
  371.     goto top;
  372.     }
  373.     c = Dredc();
  374.     if (c == '$' && flag) {
  375.     Dgetdol();
  376.     goto top;
  377.     }
  378.     return (c);
  379. }
  380.  
  381. static Char *nulvec[] = {0};
  382. static struct varent nulargv = {nulvec, STRargv, 0};
  383.  
  384. static void
  385. dolerror(s)
  386.     Char   *s;
  387. {
  388.     setname(short2str(s));
  389.     stderror(ERR_NAME | ERR_RANGE);
  390. }
  391.  
  392. /*
  393.  * Handle the multitudinous $ expansion forms.
  394.  * Ugh.
  395.  */
  396. static void
  397. Dgetdol()
  398. {
  399.     register Char *np;
  400.     register struct varent *vp = NULL;
  401.     Char    name[4 * MAXVARLEN + 1];
  402.     int     c, sc;
  403.     int     subscr = 0, lwb = 1, upb = 0;
  404.     bool    dimen = 0, bitset = 0;
  405.     char    tnp;
  406.     Char    wbuf[BUFSIZE];
  407.     static Char *dolbang = NULL;
  408.  
  409. #ifdef COMPAT
  410.     dolmod = dolmcnt = dolwcnt = 0;
  411. #else
  412.     dolnmod = dolmcnt = dolwcnt = 0;
  413. #endif /* COMPAT */
  414.     c = sc = DgetC(0);
  415.     if (c == '{')
  416.     c = DgetC(0);        /* sc is { to take } later */
  417.     if ((c & TRIM) == '#')
  418.     dimen++, c = DgetC(0);    /* $# takes dimension */
  419.     else if (c == '?')
  420.     bitset++, c = DgetC(0);    /* $? tests existence */
  421.     switch (c) {
  422.  
  423.     case '!':
  424.     if (dimen || bitset)
  425.         stderror(ERR_SYNTAX);
  426.     if (backpid != 0) {
  427.         if (dolbang) 
  428.         xfree((ptr_t) dolbang);
  429.         setDolp(dolbang = putn(backpid));
  430.     }
  431.     goto eatbrac;
  432.  
  433.     case '$':
  434.     if (dimen || bitset)
  435.         stderror(ERR_SYNTAX);
  436.     setDolp(doldol);
  437.     goto eatbrac;
  438.  
  439.     case '<' | QUOTE:
  440.     if (bitset)
  441.         stderror(ERR_NOTALLOWED, "$?<");
  442.     if (dimen)
  443.         stderror(ERR_NOTALLOWED, "$?#");
  444.     for (np = wbuf; read(OLDSTD, &tnp, 1) == 1; np++) {
  445.         *np = tnp;
  446.         if (np >= &wbuf[BUFSIZE - 1])
  447.         stderror(ERR_LTOOLONG);
  448.         if (SIGN_EXTEND_CHAR(tnp) <= 0 || tnp == '\n')
  449.         break;
  450.     }
  451.     *np = 0;
  452.     /*
  453.      * KLUDGE: dolmod is set here because it will cause setDolp to call
  454.      * domod and thus to copy wbuf. Otherwise setDolp would use it
  455.      * directly. If we saved it ourselves, no one would know when to free
  456.      * it. The actual function of the 'q' causes filename expansion not to
  457.      * be done on the interpolated value.
  458.      */
  459. #ifdef COMPAT
  460.     dolmod = 'q';
  461. #else
  462.     dolmod[dolnmod++] = 'q';
  463. #endif /* COMPAT */
  464.     dolmcnt = 10000;
  465.     setDolp(wbuf);
  466.     goto eatbrac;
  467.  
  468.     case DEOF:
  469.     case '\n':
  470.     stderror(ERR_SYNTAX);
  471.     /* NOTREACHED */
  472.     break;
  473.  
  474.     case '*':
  475.     (void) Strcpy(name, STRargv);
  476.     vp = adrof(STRargv);
  477.     subscr = -1;        /* Prevent eating [...] */
  478.     break;
  479.  
  480.     default:
  481.     np = name;
  482.     if (Isdigit(c)) {
  483.         if (dimen)
  484.         stderror(ERR_NOTALLOWED, "$#<num>");
  485.         subscr = 0;
  486.         do {
  487.         subscr = subscr * 10 + c - '0';
  488.         c = DgetC(0);
  489.         } while (Isdigit(c));
  490.         unDredc(c);
  491.         if (subscr < 0) {
  492.         dolerror(vp->v_name);
  493.         return;
  494.         }
  495.         if (subscr == 0) {
  496.         if (bitset) {
  497.             dolp = ffile ? STR1 : STR0;
  498.             goto eatbrac;
  499.         }
  500.         if (ffile == 0)
  501.             stderror(ERR_DOLZERO);
  502.         fixDolMod();
  503.         setDolp(ffile);
  504.         goto eatbrac;
  505.         }
  506.         if (bitset)
  507.         stderror(ERR_DOLQUEST);
  508.         vp = adrof(STRargv);
  509.         if (vp == 0) {
  510.         vp = &nulargv;
  511.         goto eatmod;
  512.         }
  513.         break;
  514.     }
  515.     if (!alnum(c))
  516.         stderror(ERR_VARALNUM);
  517.     for (;;) {
  518.         *np++ = c;
  519.         c = DgetC(0);
  520.         if (!alnum(c))
  521.         break;
  522.         if (np >= &name[MAXVARLEN])
  523.         stderror(ERR_VARTOOLONG);
  524.     }
  525.     *np++ = 0;
  526.     unDredc(c);
  527.     vp = adrof(name);
  528.     }
  529.     if (bitset) {
  530.     dolp = (vp || getenv(short2str(name))) ? STR1 : STR0;
  531.     goto eatbrac;
  532.     }
  533.     if (vp == 0) {
  534.     np = str2short(getenv(short2str(name)));
  535.     if (np) {
  536.         fixDolMod();
  537.         setDolp(np);
  538.         goto eatbrac;
  539.     }
  540.     udvar(name);
  541.     /* NOTREACHED */
  542.     }
  543.     c = DgetC(0);
  544.     upb = blklen(vp->vec);
  545.     if (dimen == 0 && subscr == 0 && c == '[') {
  546.     np = name;
  547.     for (;;) {
  548.         c = DgetC(DODOL);    /* Allow $ expand within [ ] */
  549.         if (c == ']')
  550.         break;
  551.         if (c == '\n' || c == DEOF)
  552.         stderror(ERR_INCBR);
  553.         if (np >= &name[sizeof(name) / sizeof(Char) - 2])
  554.         stderror(ERR_VARTOOLONG);
  555.         *np++ = c;
  556.     }
  557.     *np = 0, np = name;
  558.     if (dolp || dolcnt)    /* $ exp must end before ] */
  559.         stderror(ERR_EXPORD);
  560.     if (!*np)
  561.         stderror(ERR_SYNTAX);
  562.     if (Isdigit(*np)) {
  563.         int     i;
  564.  
  565.         for (i = 0; Isdigit(*np); i = i * 10 + *np++ - '0')
  566.         continue;
  567.         if ((i < 0 || i > upb) && !any("-*", *np)) {
  568.         dolerror(vp->v_name);
  569.         return;
  570.         }
  571.         lwb = i;
  572.         if (!*np)
  573.         upb = lwb, np = STRstar;
  574.     }
  575.     if (*np == '*')
  576.         np++;
  577.     else if (*np != '-')
  578.         stderror(ERR_MISSING, '-');
  579.     else {
  580.         register int i = upb;
  581.  
  582.         np++;
  583.         if (Isdigit(*np)) {
  584.         i = 0;
  585.         while (Isdigit(*np))
  586.             i = i * 10 + *np++ - '0';
  587.         if (i < 0 || i > upb) {
  588.             dolerror(vp->v_name);
  589.             return;
  590.         }
  591.         }
  592.         if (i < lwb)
  593.         upb = lwb - 1;
  594.         else
  595.         upb = i;
  596.     }
  597.     if (lwb == 0) {
  598.         if (upb != 0) {
  599.         dolerror(vp->v_name);
  600.         return;
  601.         }
  602.         upb = -1;
  603.     }
  604.     if (*np)
  605.         stderror(ERR_SYNTAX);
  606.     }
  607.     else {
  608.     if (subscr > 0)
  609.         if (subscr > upb)
  610.         lwb = 1, upb = 0;
  611.         else
  612.         lwb = upb = subscr;
  613.     unDredc(c);
  614.     }
  615.     if (dimen) {
  616.     Char   *cp = putn(upb - lwb + 1);
  617.  
  618.     addla(cp);
  619.     xfree((ptr_t) cp);
  620.     }
  621.     else {
  622. eatmod:
  623.     fixDolMod();
  624.     dolnxt = &vp->vec[lwb - 1];
  625.     dolcnt = upb - lwb + 1;
  626.     }
  627. eatbrac:
  628.     if (sc == '{') {
  629.     c = Dredc();
  630.     if (c != '}')
  631.         stderror(ERR_MISSING, '}');
  632.     }
  633. }
  634.  
  635. static void
  636. fixDolMod()
  637. {
  638.     register int c;
  639.  
  640.     c = DgetC(0);
  641.     if (c == ':') {
  642. #ifndef COMPAT
  643.     do {
  644. #endif /* COMPAT */
  645.         c = DgetC(0), dolmcnt = 1, dolwcnt = 1;
  646.         if (c == 'g' || c == 'a') {
  647.         if (c == 'g')
  648.             dolmcnt = 10000;
  649.         else
  650.             dolwcnt = 10000;
  651.         c = DgetC(0);
  652.         }
  653.         if ((c == 'g' && dolmcnt != 10000) || 
  654.         (c == 'a' && dolwcnt != 10000)) {
  655.         if (c == 'g')
  656.             dolmcnt = 10000;
  657.         else
  658.             dolwcnt = 10000;
  659.         c = DgetC(0); 
  660.         }
  661.  
  662.         if (c == 's') {    /* [eichin:19910926.0755EST] */
  663.         int delimcnt = 2;
  664.         int delim = DgetC(0);
  665.         dolmod[dolnmod++] = c;
  666.         dolmod[dolnmod++] = delim;
  667.         
  668.         if (!delim || letter(delim)
  669.             || Isdigit(delim) || any(" \t\n", delim)) {
  670.             seterror(ERR_BADSUBST);
  671.             break;
  672.         }    
  673.         while ((c = DgetC(0)) != (-1)) {
  674.             dolmod[dolnmod++] = c;
  675.             if(c == delim) delimcnt--;
  676.             if(!delimcnt) break;
  677.         }
  678.         if(delimcnt) {
  679.             seterror(ERR_BADSUBST);
  680.             break;
  681.         }
  682.         continue;
  683.         }
  684.         if (!any("htrqxes", c))
  685.         stderror(ERR_BADMOD, c);
  686. #ifndef COMPAT
  687.         dolmod[dolnmod++] = c;
  688. #else
  689.         dolmod = c;
  690. #endif /* COMPAT */
  691.         if (c == 'q')
  692.         dolmcnt = 10000;
  693. #ifndef COMPAT
  694.     }
  695.     while ((c = DgetC(0)) == ':');
  696.     unDredc(c);
  697. #endif /* COMPAT */
  698.     }
  699.     else
  700.     unDredc(c);
  701. }
  702.  
  703. static void
  704. setDolp(cp)
  705.     register Char *cp;
  706. {
  707.     register Char *dp;
  708. #ifndef COMPAT
  709.     int i;
  710. #endif /* COMPAT */
  711.  
  712. #ifdef COMPAT
  713.     if (dolmod == 0 || dolmcnt == 0) {
  714. #else
  715.     if (dolnmod == 0 || dolmcnt == 0) {
  716. #endif /* COMPAT */
  717.     dolp = cp;
  718.     return;
  719.     }
  720. #ifdef COMPAT
  721.     dp = domod(cp, dolmod);
  722. #else
  723.     dp = cp = Strsave(cp);
  724.     for (i = 0; i < dolnmod; i++) {
  725.     /* handle s// [eichin:19910926.0510EST] */
  726.     if(dolmod[i] == 's') {
  727.         int delim;
  728.         Char *lhsub, *rhsub, *np;
  729.         size_t lhlen = 0, rhlen = 0;
  730.         int didmod = 0;
  731.         
  732.         delim = dolmod[++i];
  733.         if (!delim || letter(delim)
  734.         || Isdigit(delim) || any(" \t\n", delim)) {
  735.         seterror(ERR_BADSUBST);
  736.         break;
  737.         }
  738.         lhsub = &dolmod[++i];
  739.         while(dolmod[i] != delim && dolmod[++i]) {
  740.         lhlen++;
  741.         }
  742.         dolmod[i] = 0;
  743.         rhsub = &dolmod[++i];
  744.         while(dolmod[i] != delim && dolmod[++i]) {
  745.         rhlen++;
  746.         }
  747.         dolmod[i] = 0;
  748.  
  749.         do {
  750.         dp = Strstr(cp, lhsub);
  751.         if (dp) {
  752.             np = (Char *) xmalloc((size_t)
  753.                       ((Strlen(cp) + 1 - lhlen + rhlen) *
  754.                       sizeof(Char)));
  755.             (void) Strncpy(np, cp, dp - cp);
  756.             (void) Strcpy(np + (dp - cp), rhsub);
  757.             (void) Strcpy(np + (dp - cp) + rhlen, dp + lhlen);
  758.  
  759.             xfree((ptr_t) cp);
  760.             dp = cp = np;
  761.             didmod = 1;
  762.         } else {
  763.             /* should this do a seterror? */
  764.             break;
  765.         }
  766.         }
  767.         while (dolwcnt == 10000);
  768.         /*
  769.          * restore dolmod for additional words
  770.          */
  771.         dolmod[i] = rhsub[-1] = delim;
  772.         if (didmod)
  773.         dolmcnt--;
  774.         else
  775.         break;
  776.         } else {
  777.         int didmod = 0;
  778.  
  779.         do {
  780.         if ((dp = domod(cp, dolmod[i]))) {
  781.             didmod = 1;
  782.             if (Strcmp(cp, dp) == 0) {
  783.             xfree((ptr_t) cp);
  784.             cp = dp;
  785.             break;
  786.             }
  787.             else {
  788.             xfree((ptr_t) cp);
  789.             cp = dp;
  790.             }
  791.         }
  792.         else
  793.             break;
  794.         }
  795.         while (dolwcnt == 10000);
  796.         dp = cp;
  797.         if (didmod)
  798.         dolmcnt--;
  799.         else
  800.         break;
  801.     }
  802.     }
  803. #endif /* COMPAT */
  804.  
  805.     if (dp) {
  806. #ifdef COMPAT
  807.     dolmcnt--;
  808. #endif /* COMPAT */
  809.     addla(dp);
  810.     xfree((ptr_t) dp);
  811.     }
  812. #ifndef COMPAT
  813.     else
  814.     addla(cp);
  815. #endif /* COMPAT */
  816.  
  817.     dolp = STRNULL;
  818.     if (seterr)
  819.     stderror(ERR_OLD);
  820. }
  821.  
  822. static void
  823. unDredc(c)
  824.     int     c;
  825. {
  826.  
  827.     Dpeekrd = c;
  828. }
  829.  
  830. static int
  831. Dredc()
  832. {
  833.     register int c;
  834.  
  835.     if (c = Dpeekrd) {
  836.     Dpeekrd = 0;
  837.     return (c);
  838.     }
  839.     if (Dcp && (c = *Dcp++))
  840.     return (c & (QUOTE | TRIM));
  841.     if (*Dvp == 0) {
  842.     Dcp = 0;
  843.     return (DEOF);
  844.     }
  845.     Dcp = *Dvp++;
  846.     return (' ');
  847. }
  848.  
  849. static void
  850. Dtestq(c)
  851.     register int c;
  852. {
  853.  
  854.     if (cmap(c, QUOTES))
  855.     gflag = 1;
  856. }
  857.  
  858. /*
  859.  * Form a shell temporary file (in unit 0) from the words
  860.  * of the shell input up to EOF or a line the same as "term".
  861.  * Unit 0 should have been closed before this call.
  862.  */
  863. void
  864. heredoc(term)
  865.     Char   *term;
  866. {
  867.     register int c;
  868.     Char   *Dv[2];
  869.     Char    obuf[BUFSIZE], lbuf[BUFSIZE], mbuf[BUFSIZE];
  870.     int     ocnt, lcnt, mcnt;
  871.     register Char *lbp, *obp, *mbp;
  872.     Char  **vp;
  873.     bool    quoted;
  874.     char   *tmp;
  875.  
  876.     if (creat(tmp = short2str(shtemp), 0600) < 0)
  877.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  878.     (void) close(0);
  879.     if (open(tmp, O_RDWR) < 0) {
  880.     int     oerrno = errno;
  881.  
  882.     (void) unlink(tmp);
  883.     errno = oerrno;
  884.     stderror(ERR_SYSTEM, tmp, strerror(errno));
  885.     }
  886.     (void) unlink(tmp);        /* 0 0 inode! */
  887.     Dv[0] = term;
  888.     Dv[1] = NULL;
  889.     gflag = 0;
  890.     trim(Dv);
  891.     rscan(Dv, Dtestq);
  892.     quoted = gflag;
  893.     ocnt = BUFSIZE;
  894.     obp = obuf;
  895.     for (;;) {
  896.     /*
  897.      * Read up a line
  898.      */
  899.     lbp = lbuf;
  900.     lcnt = BUFSIZE - 4;
  901.     for (;;) {
  902.         c = readc(1);    /* 1 -> Want EOF returns */
  903.         if (c < 0 || c == '\n')
  904.         break;
  905.         if (c &= TRIM) {
  906.         *lbp++ = c;
  907.         if (--lcnt < 0) {
  908.             setname("<<");
  909.             stderror(ERR_NAME | ERR_OVERFLOW);
  910.         }
  911.         }
  912.     }
  913.     *lbp = 0;
  914.  
  915.     /*
  916.      * Check for EOF or compare to terminator -- before expansion
  917.      */
  918.     if (c < 0 || eq(lbuf, term)) {
  919.         (void) write(0, short2str(obuf), (size_t) (BUFSIZE - ocnt));
  920.         (void) lseek(0, 0l, L_SET);
  921.         return;
  922.     }
  923.  
  924.     /*
  925.      * If term was quoted or -n just pass it on
  926.      */
  927.     if (quoted || noexec) {
  928.         *lbp++ = '\n';
  929.         *lbp = 0;
  930.         for (lbp = lbuf; c = *lbp++;) {
  931.         *obp++ = c;
  932.         if (--ocnt == 0) {
  933.             (void) write(0, short2str(obuf), BUFSIZE);
  934.             obp = obuf;
  935.             ocnt = BUFSIZE;
  936.         }
  937.         }
  938.         continue;
  939.     }
  940.  
  941.     /*
  942.      * Term wasn't quoted so variable and then command expand the input
  943.      * line
  944.      */
  945.     Dcp = lbuf;
  946.     Dvp = Dv + 1;
  947.     mbp = mbuf;
  948.     mcnt = BUFSIZE - 4;
  949.     for (;;) {
  950.         c = DgetC(DODOL);
  951.         if (c == DEOF)
  952.         break;
  953.         if ((c &= TRIM) == 0)
  954.         continue;
  955.         /* \ quotes \ $ ` here */
  956.         if (c == '\\') {
  957.         c = DgetC(0);
  958.         if (!any("$\\`", c))
  959.             unDgetC(c | QUOTE), c = '\\';
  960.         else
  961.             c |= QUOTE;
  962.         }
  963.         *mbp++ = c;
  964.         if (--mcnt == 0) {
  965.         setname("<<");
  966.         stderror(ERR_NAME | ERR_OVERFLOW);
  967.         }
  968.     }
  969.     *mbp++ = 0;
  970.  
  971.     /*
  972.      * If any ` in line do command substitution
  973.      */
  974.     mbp = mbuf;
  975.     if (any(short2str(mbp), '`')) {
  976.         /*
  977.          * 1 arg to dobackp causes substitution to be literal. Words are
  978.          * broken only at newlines so that all blanks and tabs are
  979.          * preserved.  Blank lines (null words) are not discarded.
  980.          */
  981.         vp = dobackp(mbuf, 1);
  982.     }
  983.     else
  984.         /* Setup trivial vector similar to return of dobackp */
  985.         Dv[0] = mbp, Dv[1] = NULL, vp = Dv;
  986.  
  987.     /*
  988.      * Resurrect the words from the command substitution each separated by
  989.      * a newline.  Note that the last newline of a command substitution
  990.      * will have been discarded, but we put a newline after the last word
  991.      * because this represents the newline after the last input line!
  992.      */
  993.     for (; *vp; vp++) {
  994.         for (mbp = *vp; *mbp; mbp++) {
  995.         *obp++ = *mbp & TRIM;
  996.         if (--ocnt == 0) {
  997.             (void) write(0, short2str(obuf), BUFSIZE);
  998.             obp = obuf;
  999.             ocnt = BUFSIZE;
  1000.         }
  1001.         }
  1002.         *obp++ = '\n';
  1003.         if (--ocnt == 0) {
  1004.         (void) write(0, short2str(obuf), BUFSIZE);
  1005.         obp = obuf;
  1006.         ocnt = BUFSIZE;
  1007.         }
  1008.     }
  1009.     if (pargv)
  1010.         blkfree(pargv), pargv = 0;
  1011.     }
  1012. }
  1013.